﻿//+------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description: OS Feature Display names.
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Resources;
using System.Threading;
using VmroleAuthor.Helpers;
using VmroleAuthor.Properties;

namespace VmroleAuthor.Models
{

    [TypeConverter(typeof(OSFeatureTypeHelper))]
    public enum OSFeatureType
    {
        Role = 0,
        RoleService = 1,
        Feature = 2
    }

    public class OSFeatureTypeHelper : TypeConverterEnumHelper<OSFeatureType>
    {
        private static readonly LocalizableEnumHelper<OSFeatureType> Helper =
            new LocalizableEnumHelper<OSFeatureType>(Resources.ResourceManager);

        public OSFeatureTypeHelper()
            : base(Helper)
        {
        }

        /// <summary>
        /// Get the localized name for the given object type
        /// </summary>
        public static string GetName(OSFeatureType type)
        {
            return OSFeatureTypeHelper.Helper.GetName(type);
        }
    }


    [TypeConverter(typeof(OSFeatureDisplayNameEnumHelper))]
    public enum OSFeatureDisplayNameEnum
    {
        ActiveDirectoryCertificateServices = 0,
        CertificationAuthority = 1,
        CertificationAuthorityWebEnrollment = 2,
        OnlineResponder = 3,
        NetworkDeviceEnrollmentService = 4,
        CertificateEnrollmentWebService = 5,
        CertificateEnrollmentPolicyWebService = 6,
        ActiveDirectoryDomainServices = 7,
        ActiveDirectoryDomainController = 8,
        IdentityManagementforUNIX = 9,
        ServerforNetworkInformationServices = 10,
        PasswordSynchronization = 11,
        AdministrationTools = 12,
        ActiveDirectoryFederationServices = 13,
        FederationService = 14,
        FederationServiceProxy = 15,
        ADFSWebAgents = 16,
        ClaimsawareAgent = 17,
        WindowsTokenbasedAgent = 18,
        ActiveDirectoryLightweightDirectoryServices = 19,
        ActiveDirectoryRightsManagementServices = 20,
        ActiveDirectorRightsManagementServer = 21,
        IdentityFederationSupport = 22,
        ApplicationServer = 23,
        NETFramework351 = 24,
        WebServerIISSupport = 25,
        COMNetworkAccess = 26,
        TCPPortSharing = 27,
        WindowsProcessActivationServiceSupport = 28,
        HTTPActivation = 29,
        MessageQueuingActivation = 30,
        TCPActivation = 31,
        NamedPipesActivation = 32,
        DistributedTransactions = 33,
        IncomingRemoteTransactions = 34,
        OutgoingRemoteTransactions = 35,
        WSAtomicTransactions = 36,
        DHCPServer = 37,
        DNSServer = 38,
        FaxServer = 39,
        FileServices = 40,
        FileServer = 41,
        DistributedFileSystem = 42,
        DFSNamespaces = 43,
        DFSReplication = 44,
        FileServerResourceManager = 45,
        ServicesforNetworkFileSystem = 46,
        WindowsSearchService = 47,
        WindowsServer2003FileServices = 48,
        IndexingService = 49,
        BranchCacheforNetworkFiles = 50,
        HyperV = 51,
        NetworkPolicyandAccessServices = 52,
        NetworkPolicyServer = 53,
        RoutingandRemoteAccessServices = 54,
        RemoteAccessService = 55,
        Routing = 56,
        HealthRegistrationAuthority = 57,
        HostCredentialAuthorizationProtocol = 58,
        PrintandDocumentServices = 59,
        PrintServer = 60,
        LPDService = 61,
        InternetPrinting = 62,
        DistributedScanServer = 63,
        RemoteDesktopServices = 64,
        RemoteDesktopSessionHost = 65,
        RemoteDesktopVirtualizationHost = 66,
        RemoteDesktopLicensing = 67,
        RemoteDesktopConnectionBroker = 68,
        RemoteDesktopGateway = 69,
        RemoteDesktopWebAccess = 70,
        WebServerIIS = 71,
        WebServer = 72,
        CommonHTTPFeatures = 73,
        StaticContent = 74,
        DefaultDocument = 75,
        DirectoryBrowsing = 76,
        HTTPErrors = 77,
        HTTPRedirection = 78,
        WebDAVPublishing = 79,
        ApplicationDevelopment = 80,
        ASPNET = 81,
        NETExtensibility = 82,
        ASP = 83,
        CGI = 84,
        ISAPIExtensions = 85,
        ISAPIFilters = 86,
        ServerSideIncludes = 87,
        HealthandDiagnostics = 88,
        HTTPLogging = 89,
        LoggingTools = 90,
        RequestMonitor = 91,
        Tracing = 92,
        CustomLogging = 93,
        ODBCLogging = 94,
        Security = 95,
        BasicAuthentication = 96,
        WindowsAuthentication = 97,
        DigestAuthentication = 98,
        ClientCertificateMappingAuthentication = 99,
        IISClientCertificateMappingAuthentication = 100,
        URLAuthorization = 101,
        RequestFiltering = 102,
        IPandDomainRestrictions = 103,
        Performance = 104,
        StaticContentCompression = 105,
        DynamicContentCompression = 106,
        ManagementTools = 107,
        IISManagementConsole = 108,
        IISManagementScriptsandTools = 109,
        ManagementService = 110,
        IIS6ManagementCompatibility = 111,
        IIS6MetabaseCompatibility = 112,
        IIS6WMICompatibility = 113,
        IIS6ScriptingTools = 114,
        IIS6ManagementConsole = 115,
        FTPServer = 116,
        FTPService = 117,
        FTPExtensibility = 118,
        IISHostableWebCore = 119,
        WindowsDeploymentServices = 120,
        DeploymentServer = 121,
        TransportServer = 122,
        WindowsServerUpdateServices = 123,
        NETFramework351Features = 124,
        NETFramework351Core = 125,
        WCFActivation = 126,
        NETHTTPActivation = 127,
        NonHTTPActivation = 128,
        BackgroundIntelligentTransferServiceBITS = 129,
        CompactServer = 130,
        IISServerExtension = 131,
        BitLockerDriveEncryption = 132,
        BranchCache = 133,
        ConnectionManagerAdministrationKit = 134,
        DesktopExperience = 135,
        DirectAccessManagementConsole = 136,
        FailoverClustering = 137,
        GroupPolicyManagement = 138,
        InkandHandwritingServices = 139,
        InkSupport = 140,
        HandwritingRecognition = 141,
        InternetPrintingClient = 142,
        InternetStorageNameServer = 143,
        LPRPortMonitor = 144,
        MessageQueuing = 145,
        MessageQueuingServices = 146,
        MessageQueuingServer = 147,
        DirectoryServiceIntegration = 148,
        MessageQueuingTriggers = 149,
        HTTPSupport = 150,
        MulticastingSupport = 151,
        RoutingService = 152,
        MessageQueuingDCOMProxy = 153,
        MultipathIO = 154,
        NetworkLoadBalancing = 155,
        PeerNameResolutionProtocol = 156,
        QualityWindowsAudioVideoExperience = 157,
        RemoteAssistance = 158,
        RemoteDifferentialCompression = 159,
        RemoteServerAdministrationTools = 160,
        RoleAdministrationTools = 161,
        ActiveDirectoryCertificateServicesTools = 162,
        CertificationAuthorityTools = 163,
        OnlineResponderTools = 164,
        ADDSandADLDSTools = 165,
        ADDSTools = 166,
        ADDSSnapInsandCommandLineTools = 167,
        ActiveDirectoryAdministrativeCenter = 168,
        ServerforNISTools = 169,
        ADLDSSnapInsandCommandLineTools = 170,
        ActiveDirectoryModuleforWindowsPowerShell = 171,
        ActiveDirectoryRightsManagementServicesTools = 172,
        DHCPServerTools = 173,
        DNSServerTools = 174,
        FaxServerTools = 175,
        FileServicesTools = 176,
        DistributedFileSystemTools = 177,
        FileServerResourceManagerTools = 178,
        ServicesforNetworkFileSystemTools = 179,
        HyperVTools = 180,
        NetworkPolicyandAccessServicesTools = 181,
        PrintandDocumentServicesTools = 182,
        RemoteDesktopServicesTools = 183,
        RemoteDesktopSessionHostTools = 184,
        RemoteDesktopGatewayTools = 185,
        RemoteDesktopLicensingTools = 186,
        RemoteDesktopConnectionBrokerTools = 187,
        WebServerIISTools = 188,
        WindowsDeploymentServicesTools = 189,
        FeatureAdministrationTools = 190,
        BitLockerDriveEncryptionAdministrationUtilities = 191,
        BitLockerDriveEncryptionTools = 192,
        BitLockerRecoveryPasswordViewer = 193,
        BITSServerExtensionsTools = 194,
        FailoverClusteringTools = 195,
        NetworkLoadBalancingTools = 196,
        SMTPServerTools = 197,
        WINSServerTools = 198,
        RPCoverHTTPProxy = 199,
        SimpleTCPIPServices = 200,
        SMTPServer = 201,
        SNMPServices = 202,
        SNMPService = 203,
        SNMPWMIProvider = 204,
        StorageManagerforSANs = 205,
        SubsystemforUNIXbasedApplications = 206,
        TelnetClient = 207,
        TelnetServer = 208,
        TFTPClient = 209,
        WindowsBiometricFramework = 210,
        WindowsInternalDatabase = 211,
        WindowsPowerShellIntegratedScriptingEnvironmentISE = 212,
        WindowsProcessActivationService = 213,
        ProcessModel = 214,
        NETEnvironment = 215,
        ConfigurationAPIs = 216,
        WindowsServerBackupFeatures = 217,
        WindowsServerBackup = 218,
        CommandlineTools = 219,
        WindowsServerMigrationTools = 220,
        WindowsSystemResourceManager = 221,
        WindowsTIFFIFilter = 222,
        WinRMIISExtension = 223,
        WINSServer = 224,
        WirelessLANService = 225,
        XPSViewer = 226,

        // Server core only features
        WoW64Support = 227,
        WoW64 = 228,
        WoW64forNETFramework20andWindowsPowerShell = 229,
        WoW64forNETFramework20 = 230,
        WoW64forWindowsPowerShell = 231,
        WOW64forNETFramework30and35 = 232,
        WoW64forPrintServices = 233,
        WoW64forFailoverClustering = 234,
        WoW64forInputMethodEditor = 235,
        WoW64forSubsystemforUNIXbasedApplications = 236,

        //Win 8 only features
        FileAndStorageServices = 237,
        DataDeduplication = 238,
        FileServerVSSAgentService = 239,
        iSCSITargetServer = 240,
        iSCSITargetStorageProvider = 241,
        ServerForNFS = 242,
        StorageServices = 243,
        RemoteAccess = 244,
        DirectAccessAndVPN = 245,
        RoutingWin8 = 246,
        WindowsStandardsBasedStorageManagement = 247,
        VolumeActivationServices = 248,
        CentralizedSSLCertificateSupport = 249,
        NETExtensibility45 = 250,
        ApplicationInitialization = 251,
        ASPNET45 = 252,
        WebSocketProtocol = 253,
        WindowsServerUpdateServicesWin8 = 254,
        WIDDatabase = 255,
        WSUSServices = 256,
        Database = 257,
        NETFramework35Features = 258,
        NETFramework45Features = 259,
        NETFramework45 = 260,
        ASPNET45Win8 = 261,
        WCFServices = 262,
        HTTPActivationWin8 = 263,
        MessageQueuingActivationWin8 = 264,
        NamedPipeActivation = 265,
        TCPActivationWin8 = 266,
        TCPPortSharingWin8 = 267,
        ClientForNFS = 268,
        DataCenterBridging = 269,
        EnhancedStorage = 270,
        BitLockerNetworkUnlock = 271,
        IPAddressManagementServer = 272,
        ManagementODataIISExtension = 273,
        MediaFoundation = 274,
        FailoverClusterManagementTools = 275,
        FailoverClusterModuleForWindowsPowerShell = 276,
        FailoverClusterAutomationServer = 277,
        FailoverClusterCommandInterface = 278,
        IPAddressManagementClient = 279,
        SNMPTools = 280,
        WindowsSystemResourceManagerRSAT = 281,
        HyperVManagementTools = 282,
        HyperVModuleForWindowsPowerShell = 283,
        RemoteDesktopServicesToolsWin8 = 284,
        RemoteDesktopLicensingDiagnoserTools = 285,
        WindowsServerUpdateServicesTools = 286,
        APIAndPowerShellCmdlets = 287,
        UserInterfaceManagementConsole = 288,
        ActiveDirectoryRightsManagementServicesToolsWin8 = 289,
        ShareAndStorageManagementTool = 290,
        NetworkPolicyAndAccessServicesToolsWin8 = 291,
        RemoteAccessManagementTools = 292,
        RemoteAccessGUIAndCommandLineTools = 293,
        RemoteAccessModuleForWindowsPowerShell = 294,
        VolumeActivationTools = 295,
        UserInterfacesAndInfrastructure = 296,
        GraphicalManagementToolsAndInfrastructure = 297,
        ServerGraphicalShell = 298,
        WindowsPowerShell = 299,
        WindowsPowerShell30 = 300,
        WindowsPowerShell20Engine = 301,
        WindowsFeedbackForwarder = 302,
        WindowsIdentityFoundation35 = 303,
        WindowsPowerShellWebAccess = 304,
        WindowsSearchServiceWin8 = 305,
        HyperVGuiManagementTools = 306,
        NetFramework35 = 307,
        iSNSServerService = 308,
        NETEnvironment35 = 309,
        RASConnectionManagerAdministrationKit = 310,
        CertificationAuthorityManagementTools = 311,
        DFSManagementTools = 312,
        ServicesForNetworkFileSystemManagementTools = 313,
        WindowsPowerShellISE = 314,

        //Windows Blue only role/features or displaynames
        Essentials = 315,
        FileAndiSCSIServices = 316,
        WorkFolders = 317,
        NETExtensibility35 = 318,
        ASPNET35 = 319,
        DirectPlay = 320,
        SMB10CIFSFileSharingSupport = 321,
        ADFS11WebAgents = 322,
        ADFS11ClaimsawareAgent = 323,
        ADFS11WindowsTokenbasedAgent = 324,
        IncomingNetworkTransactions = 325,
        OutgoingNetworkTransactions = 326,
        WebApplicationProxy = 327,      
        SMBBandwidthLimit = 330,
        WindowsPowerShellDesiredStateConfigurationService = 331,
        WindowsPowerShell40 = 332,
    }

    public interface IEnumHelper<in TEnumType>
    {
        string GetName(TEnumType value);
    }

    public class TypeConverterEnumHelper<TEnumType> : TypeConverter
      where TEnumType : struct
    {
        private readonly IEnumHelper<TEnumType> enumHelper;

        protected TypeConverterEnumHelper(IEnumHelper<TEnumType> enumHelper)
        {
            this.enumHelper = enumHelper;
        }

        #region TypeConverter overloads
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || sourceType == typeof(TEnumType);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string) || destinationType == typeof(TEnumType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            Debug.Assert(value != null, "value != null");
            if (!this.CanConvertFrom(context, value.GetType()))
            {
                throw new NotSupportedException();
            }

            string s = value as string;
            if (s != null)
            {
                return Enum.Parse(typeof(TEnumType), s, true);
            }
            return value;
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (!this.CanConvertTo(context, destinationType))
            {
                throw new NotSupportedException();
            }

            TEnumType? enumValue = value as TEnumType?;
            if (enumValue.HasValue && destinationType == typeof(string))
            {
                return this.enumHelper.GetName(enumValue.Value);
            }
            return value;
        }
        #endregion
    }

    /// <summary>
    /// Helper class to look up enums in a resource table provided by the passed in
    /// resource manager.
    /// NOTE: Any resources for enums using this helper class must be saved in the format:
    /// "EnumType"."EnumValue"  These will be checked at static initialization time, providing
    /// more testable resource handling than using a developer-provided string table.
    /// </summary>
    /// <typeparam name="TEnumType"></typeparam>
    public class LocalizableEnumHelper<TEnumType> : IEnumHelper<TEnumType>
    {
        //For each langauge, there is a dictionary which stores each enum's type with its string representation in that language.
        private readonly Dictionary<CultureInfo, Dictionary<TEnumType, string>> cultureToEnumTableLookup;
        private readonly Dictionary<TEnumType, TEnumType[]> additionalCombinedValues;
        protected ResourceManager LocalResourceManager;
        private readonly Object syncObject = new object();
        private readonly string suffix;

        /// <summary>
        /// Look up text by "{Enum type name}{Enum value name}"
        /// </summary>
        public LocalizableEnumHelper(ResourceManager resourceManager)
            : this(resourceManager, String.Empty)
        {
        }

        /// <summary>
        /// Look up text by "{Enum type name}{Enum value name}{Suffix}"
        /// </summary>
        public LocalizableEnumHelper(ResourceManager resourceManager, string suffix)
        {
            this.suffix = suffix;
            this.LocalResourceManager = resourceManager;
            this.additionalCombinedValues = new Dictionary<TEnumType, TEnumType[]>();
            this.cultureToEnumTableLookup = new Dictionary<CultureInfo, Dictionary<TEnumType, string>>();
            this.LoadEnumValuesForCurrentCulture();
        }

        protected void LoadEnumValuesForCurrentCulture()
        {
            CultureInfo currentCulture = Thread.CurrentThread.CurrentUICulture;
            Dictionary<TEnumType, string> enumStringTable = new Dictionary<TEnumType, string>();

            string[] enumNames = Enum.GetNames(typeof(TEnumType));
            TEnumType[] enumValues = (TEnumType[])Enum.GetValues(typeof(TEnumType));

            for (int i = 0; i < enumNames.Length; ++i)
            {
                //as long as the value has a name, we're okay.
                //(we can't tell the difference between two enums with the same value)
                if (!enumStringTable.ContainsKey(enumValues[i]))
                {
                    string key = typeof(TEnumType).Name + enumNames[i] + this.suffix;
                    string localizedName = this.LocalResourceManager.GetString(key);
                    Debug.Assert(localizedName != null,
                        string.Format("Each enum in {0} must have a localizable string name. Resource {1} in {2} for value {3} undefined",
                        typeof(TEnumType).FullName, key, this.LocalResourceManager.BaseName, enumNames[i]));

                    enumStringTable.Add(enumValues[i], localizedName);
                }
            }

            this.PopulateAdditionalCombinedValues(enumStringTable);

            lock (this.syncObject)
            {
                this.cultureToEnumTableLookup[currentCulture] = enumStringTable;
            }
        }

        protected void PopulateAdditionalCombinedValues(Dictionary<TEnumType, string> enumStringTable)
        {
            //Lock so additionalCombinedValues keys collection does not change.
            lock (this.syncObject)
            {
                foreach (TEnumType key in this.additionalCombinedValues.Keys)
                {
                    if (!enumStringTable.ContainsKey(key))
                    {
                        List<string> combinedLocalizedEnums = new List<string>();
                        TEnumType[] listOfEnumsToCombine = this.additionalCombinedValues[key];

                        foreach (TEnumType enumType in listOfEnumsToCombine)
                        {
                            //Read each enum in the list and save its localized text into the new text list.
                            combinedLocalizedEnums.Add(enumStringTable[enumType]);
                        }

                        //Add combined items as a new individual item under the given key.
                        enumStringTable[key] = StringHelper.ListToCommaSeparatedString(combinedLocalizedEnums);
                    }
                }
            }
        }

        /// <summary>
        /// Takes a unique EnumType with an associated array of enums which
        /// will be registered as a new combined type, displayed as a comma delimited list
        /// of the individual enums in the list.
        /// </summary>
        /// <param name="enumValue">A unique identifier for this combination of enumtypes</param>
        /// <param name="combinedEnumList">the list of enums which are to be treated as one new enum type</param>
        public void AddCombinedValue(TEnumType enumValue, TEnumType[] combinedEnumList)
        {
            //Lock so because writing to additionalCombinedValues and so that
            //cultureToEnumTableLookup keys do not change.
            lock (this.syncObject)
            {
                if (!this.additionalCombinedValues.ContainsKey(enumValue))
                {
                    this.additionalCombinedValues.Add(enumValue, combinedEnumList);

                    //Add the additional items to all loaded cultures. Cultures loaded in the future
                    //will have the items added at load time.
                    foreach (CultureInfo culture in this.cultureToEnumTableLookup.Keys)
                    {
                        this.PopulateAdditionalCombinedValues(this.cultureToEnumTableLookup[culture]);
                    }
                }
            }
        }

        public string GetName(TEnumType state)
        {
            CultureInfo requestCulture = Thread.CurrentThread.CurrentUICulture;
            return this.GetName(state, requestCulture);
        }


        /// <summary>
        /// Get the localized name for the given object type
        /// </summary>       
        /// <returns></returns>
        public string GetName(TEnumType state, CultureInfo requestCulture)
        {
            if (!this.cultureToEnumTableLookup.ContainsKey(requestCulture))
            {
                this.LoadEnumValuesForCurrentCulture();
                Debug.Assert(this.cultureToEnumTableLookup.ContainsKey(requestCulture), "Could not find localized enum dictionary for the current culture after calling LoadEnumValuesForCurrentCulture");
            }

            Dictionary<TEnumType, string> enumStringTable = this.cultureToEnumTableLookup[requestCulture];
            Debug.Assert(enumStringTable.ContainsKey(state), "Request for an enum state was made without that state having been loaded.");
            return enumStringTable[state];
        }
    }

    public class OSFeatureDisplayNameEnumHelper : TypeConverterEnumHelper<OSFeatureDisplayNameEnum>
    {
        private static readonly LocalizableEnumHelper<OSFeatureDisplayNameEnum> Helper =
            new LocalizableEnumHelper<OSFeatureDisplayNameEnum>(Resources.ResourceManager);

        public OSFeatureDisplayNameEnumHelper()
            : base(Helper)
        {
        }

        /// <summary>
        /// Get the localized name for the given object type
        /// </summary>
        public static string GetName(OSFeatureDisplayNameEnum displayName)
        {
            return OSFeatureDisplayNameEnumHelper.Helper.GetName(displayName);
        }
    }

    [TypeConverter(typeof(OSFeatureCompatibleOSHelper))]
    public enum OSFeatureCompatibleOS
    {
        WindowsServer2008R2 = 1, //Win7
        WindowsServer2012 = 2, //Win8
        WindowsServer2012R2 = 3 //Blue
    }

    public class OSFeatureCompatibleOSHelper : TypeConverterEnumHelper<OSFeatureCompatibleOS>
    {
        private static readonly LocalizableEnumHelper<OSFeatureCompatibleOS> Helper =
            new LocalizableEnumHelper<OSFeatureCompatibleOS>(Resources.ResourceManager);

        public OSFeatureCompatibleOSHelper()
            : base(Helper)
        {
        }

        /// <summary>
        /// Get the localized name for the given object type
        /// </summary>
        public static string GetName(OSFeatureCompatibleOS os)
        {
            return OSFeatureCompatibleOSHelper.Helper.GetName(os);
        }
    }
}
